﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using devtm.Collections;
using System.Windows.Forms;

namespace devtm.Types.LazyLoading
{

    [Serializable]
    public class ResolveAssembly : IDisposable
    {


        public ResolveAssembly()
        {
            LastResolve = new List<ResolveItem>();
        }

        public void Dispose()
        {

        }

        /// <summary>
        /// Resolve the type not found
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
        {



            ResolveItem itt = new ResolveItem(args.Name);
            LastResolve.Add(itt);

            string name = args.Name.Split(',')[0];

            Assembly ass1 = FindInRepository(name);
            if (ass1 != null)
                return ass1;

                
            string Name = name + ".dll";

            if (Name.EndsWith(".resources.dll") || Name == "devtm.Editor.Configuration.XmlSerializers.dll")
                return null;

            // ----------- dll ----------------
            List<FileInfo> files = GetFile(Name).ToList();
            if (files.Count == 1)
                return Assembly.LoadFrom(files.First().FullName);
            else if (files.Count >= 1)
            {
                // que faire quand il y en a plusieurs. ?????????
                itt.Statut = StatutResolve.Success;
                return Assembly.LoadFrom(files.First().FullName);
            }


            // ----------- exe ----------------
            Name = name + ".exe";
            files = GetFile(Name).ToList();
            if (files.Count == 1)
                return Assembly.LoadFrom(files.First().FullName);
            else if (files.Count >= 1)
            {
                // que faire quand il y en a plusieurs. ?????????
                itt.Statut = StatutResolve.Success;
                return Assembly.LoadFrom(files.First().FullName);
            }

            return SearchManuellyFile(name);

        }

        private  Assembly FindInRepository(string name)
        {

            foreach (AssemblyNamespace item in ListeAssemblies.Current)
                if (item.SingleName.StartsWith(name))
                    return item.LoadAssembly(item.Filename);
                
            return null;

        }

        private Assembly SearchManuellyFile(string name)
        {
            System.Windows.Forms.OpenFileDialog frm = new System.Windows.Forms.OpenFileDialog();
            frm.Reset();
            frm.Multiselect = false;
            frm.Title = string.Format(
                System.Globalization.CultureInfo.CurrentCulture, 
                devtm.Types.Strings.LookingForTheAssembly0, 
                name
            );

            frm.InitialDirectory = ClsGetTypes.Directories.First().FullName;
            frm.Filter = string.Format("{0}|{0}.dll;{0}.exe", name);
            System.Windows.Forms.DialogResult result = frm.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                ClsGetTypes.Directories.Add(new FileInfo(frm.FileName).Directory);
                return Assembly.LoadFrom(frm.FileName);
            }
            return null;
        }

        private IEnumerable<FileInfo> GetFile(string filename)
        {

            //if (BeforeSearch != null)
            //    BeforeSearch(this, new SearchEventArgs() { });

            foreach (DirectoryInfo dir in ClsGetTypes.Directories)
                foreach (FileInfo file in dir.GetFiles(filename))
                    yield return file;
        }

        //public event EventHandler<SearchEventArgs> BeforeSearch;

        public List<ResolveItem> LastResolve { get; set; }

        private bool IsListen = false;
        
        public void Stop()
        {

            if (!IsListen)
                return;

            AppDomain.CurrentDomain.AssemblyResolve -= MyResolveEventHandler;
            IsListen = false;
        }

        public void Start()
        {

            if (IsListen)
                return;

            AppDomain.CurrentDomain.AssemblyResolve += MyResolveEventHandler;
            IsListen = true;

        }


    }

}
